#pragma once
#include "../mqcommon/helper.hpp"
#include "../mqcommon/logger.hpp"
#include "../mqcommon/msg.pb.h"
#include <unordered_map>
#include <mutex>
#include <google/protobuf/map.h>
//交换机定义类型

struct Exchange
{
    using Ptr = std::shared_ptr<Exchange>;
    std::string name;
    ExchangeType type;
    bool durable;
    bool autoDelete;
    google::protobuf::Map<std::string, std::string> args;
    Exchange(){}
    Exchange(const std::string& exchangeName, ExchangeType ExchangeType
            ,bool exchangeDurable, bool exchangeAutoDelete
            ,const google::protobuf::Map<std::string, std::string>& exchangeArgs)
        :name(exchangeName), type(ExchangeType), durable(exchangeDurable)
        , autoDelete(exchangeAutoDelete), args(exchangeArgs)
    {}
    ~Exchange() {}
    std::string serializeArgs()    //序列化args存储到sqlite里：格式key=value;
    {
        std::string str;
        for(auto& arg : args)
            str += arg.first + "=" + arg.second + ";";
        return str;
    }
    void deSerializeArgs(const std::string& str)  //反序列化args
    {
        std::vector<std::string> rows;
        SplitHelper::split(str, ";", rows);
        for(auto& row : rows)
        {
            int pos = row.find("=");
            args.insert({row.substr(0, pos), row.substr(pos + 1)});
        }
    }
};
//持久化存储，sqlite的操作类
class ExchangeMapper
{
public:
    ExchangeMapper(const std::string& dbfile)   
        :_helper(dbfile)
    {
        std::string parentDirectory = FileHelper::getParentDirectory(dbfile);
        FileHelper::createDirectory(parentDirectory);
        _helper.open();                                                 //定义了之后，会直接打开
        createTable();      //数据库文件创建，直接生产表
    }
    void createTable()
    {
        std::string create_sql = "create table if not exists exchange_table(name varchar(32) primary key, type int, durable int, auto_delete int, args varchar(64));";
        // std::string create_sql = "create table if not exists exchange_table\
        //         (name varchar(32) primary key\
        //         ,type int\
        //         ,durable int\
        //         ,auto_delete int\
        //         ,args varchar(64));";
                // ,args varchar[64]);";
        if(_helper.exec(create_sql) == false)
            abort();        //更加暴力，程序直接崩溃，生成 core dump
        // DLOG("create SQL: %s", create_sql.c_str());
    }
    void removeTable()
    {
        std::string remove_str = "drop table if exists exchange_table;";
        if(_helper.exec(remove_str) == false)
            abort();
    }
    bool insert(Exchange::Ptr ptr)
    {
        char insert_sql[1024] = {0};
        sprintf(insert_sql, "insert into exchange_table values('%s', %d, %d, %d, '%s');", 
            ptr->name.c_str(), 
            ptr->type, 
            ptr->durable, 
            ptr->autoDelete, 
            ptr->serializeArgs().c_str());
        // DLOG("insert_sql: %s", insert_sql);
        return _helper.exec(insert_sql);
    }
    bool remove(const std::string& exchangeName)
    {
        char remove_sql[1024] = {0};
        sprintf(remove_sql, "delete from exchange_table where name='%s';", exchangeName.c_str());
        return _helper.exec(remove_sql);
    }
    
    std::unordered_map<std::string, Exchange::Ptr> recovery() //恢复时使用
    {
        std::unordered_map<std::string, Exchange::Ptr> result;
        std::string select_sql = "select * from exchange_table;";
        _helper.exec(select_sql, selectCallback, &result);
        return result;
    }
    ~ExchangeMapper(){}
private:
    static int selectCallback(void* arg, int col_num, char** col_values, char** col_names)
    {
        std::unordered_map<std::string, Exchange::Ptr>* result = static_cast<std::unordered_map<std::string, Exchange::Ptr>*>(arg);
        Exchange::Ptr ptr = std::make_shared<Exchange>();
        ptr->name = col_values[0];
        ptr->type = (ExchangeType)(std::stoi(col_values[1]));
        ptr->durable = std::stoi(col_values[2]);
        ptr->autoDelete = std::stoi(col_values[3]);
        if(col_values[4]) ptr->deSerializeArgs(col_values[4]);            //这里不判断空，也不会报错,我们节约下时间
        result->insert({ptr->name, ptr});
        return 0;
    }
private:
    SqliteHelper _helper;
};
// 内存操作
class ExchangeManager
{
public:
    using Ptr = std::shared_ptr<ExchangeManager>;
    ExchangeManager(const std::string& dbfile)
        :_mapper(dbfile)
    {
        _exchanges = _mapper.recovery();
    }
    //1.声明交换机
    void declareExchange(const std::string& exchangeName, ExchangeType ExchangeType
            ,bool exchangeDurable, bool exchangeAutoDelete
            ,const google::protobuf::Map<std::string, std::string>& exchangeArgs)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        auto it = _exchanges.find(exchangeName);    //新增前，先判断是否已经存在
        if(it != _exchanges.end()) return ;
        Exchange::Ptr exchangePtr = std::make_shared<Exchange>(exchangeName, ExchangeType, exchangeDurable, exchangeAutoDelete, exchangeArgs);
        if(exchangePtr->durable)
            _mapper.insert(exchangePtr);
        _exchanges.insert({exchangePtr->name, exchangePtr});
    }
    //2.删除指定交换机
    void deleteExchange(const std::string& exchangeName)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        auto it = _exchanges.find(exchangeName);    //新增前，先判断是否已经存在
        if(it == _exchanges.end()) return;
        // if(it->second->durable == true)     //交换机删了，数据库里的也要删
            _mapper.remove(it->second->name);
        _exchanges.erase(it->second->name);
    }
    //3.获取交换机对象
    Exchange::Ptr selectExchange(const std::string& exchangeName)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        auto it = _exchanges.find(exchangeName);
        if(it == _exchanges.end()) return Exchange::Ptr();
        return _exchanges[exchangeName];
    }
    //4.判断交换机是否存在
    bool exists(const std::string& exchangeName)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        auto it = _exchanges.find(exchangeName);
        if(it == _exchanges.end()) return false;
        else return true;
    }
    //清理所有交换机
    void clear()
    {
        std::unique_lock<std::mutex> lock(_mutex);
        //_mapper.removeTable();        //这个逻辑不对
        for(auto& exchange : _exchanges)
            // if(exchange.second->durable == false)。
                _mapper.remove(exchange.second->name);
        _exchanges.clear();
    }
    size_t size()
    {
        return _exchanges.size();
    }
private:
    std::mutex _mutex;
    ExchangeMapper _mapper;             //用于恢复历史数据，sqlite数据加载到内存2.新交换机的持久化
    std::unordered_map<std::string, Exchange::Ptr> _exchanges;
};
